<?
require_once "AssertionFailedError.php";

/**
 * Thrown when an assert equals for Strings failed.
 *
 * @author Ryan Gantt
 */
class ComparisonFailure extends AssertionFailedError 
{
	private $fExpected;
	private $fActual;
	
	/**
 	 * Constructs a comparison failure.
	 *
	 * @param message the identifying message or null
	 * @param expected the expected string value
	 * @param actual the actual string value
	 */
	public function __construct( $message, $expected, $actual ) 
	{
		parent::__construct( $message );
		$this->fExpected = $expected;
		$this->fActual = $actual;
	}
	
	/**
	 * Returns "..." in place of common prefix and "..." in
	 * place of common suffix between expected and actual.
	 * 
	 * @see java.lang.Throwable#getMessage()
	 */
	public function _getMessage()
	{
		if ( $this->fExpected == null || $this->fActual == null )
			return Assert::format( parent::getMessage(), $this->fExpected, $this->fActual );
		$end = min( strlen( $this->fExpected ), strlen( $this->fActual ) );
		$i = 0;
		for( ; $i < $end; $i++ ) 
		{
			if ( $this->fExpected{ $i } != $this->fActual{ $i } )
				break;
		}
		$j = strlen( $this->fExpected ) - 1;
		$k = strlen( $this->fActual ) - 1;
		for ( ; $k >= $i && $j >= $i; $k--, $j-- ) 
		{
			if ( $this->fExpected{ $j } != $this->fActual{ $k } )
				break;
		}
		$actual = null;
		$expected = null;
		// equal strings
		if ( $j < $i && $k < $i ) 
		{
			$expected = $this->fExpected;
			$actual = $this->fActual;
		} 
		else 
		{
			$expected = substr( $this->fExpected, $i, $j + 1 );
			$actual = substr( $this->fActual, $i, $k + 1 );
			if ( $i <= $end && $i > 0 ) 
			{
				$expected = "..." . $expected;
				$actual = "..." . $actual;
			}
			if ($j < strlen($this->fExpected) - 1)
				$expected .= "...";
			if ($k < strlen($this->fActual) - 1)
				$actual .= "...";
		}	
		return Assert::format( parent::getMessage(), $expected, $actual );
	}
}